home *** CD-ROM | disk | FTP | other *** search
- /* -*- C -*-
- * GENCODE.C
- *
- * (c)Copyright 1995 by Tobias Ferber, All Rights Reserved.
- *
- * This file is part of ADOC.
- *
- * ADOC is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 1 of the License,
- * or (at your option) any later version.
- *
- * ADOC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /* $VER: $Id: gencode.c,v 1.10 1995/03/20 18:44:19 tf Exp $ */
-
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <stdio.h>
-
- #include "libfun.h"
- #include "adoc.h"
-
-
- /* convert tabs in `s' to spaces with a tab step of `ts' */
-
- static void fexpand(FILE *fp, int ts, char *s)
- {
- int column= 0;
-
- while(*s)
- {
- switch(*s)
- {
- case '\n':
- fputc(*s,fp);
- column= 0;
- break;
-
- case '\t':
- do { fputc(' ',fp); } while( (++column) % ts);
- break;
-
- default:
- fputc(*s,fp);
- ++column;
- break;
- }
- ++s;
- }
- }
-
-
- /*
- ** AUTODOCS
- */
-
- int gen_autodoc_toc(FILE *fp)
- {
- char *fun;
-
- fprintf(fp,"TABLE OF CONTENTS\n\n");
-
- for(fun= stepfun(0); fun; fun= stepfun(1))
- fprintf(fp,"%s\n",fun);
-
- return 0;
- }
-
-
- int gen_autodoc(FILE *fp, int cols, int tabsize, int flags, char **body_macros)
- {
- int err= 0;
-
- char *fun, *sec, *text;
-
- for(fun= stepfun(0); fun && (err==0); fun= stepfun(1))
- {
- if(flags & ADOC_FORM_FEEDS)
- fputc('\f',fp);
-
- fprintf(fp,"%s%*s\n\n",fun,(int)(cols-strlen(fun)),fun);
-
- for(sec= stepsec(0); sec && (err==0); sec= stepsec(1))
- {
- /* indent the section heading with 3 spaces */
- fprintf(fp," %s\n",sec);
-
- if( (text= getsec(sec)) )
- {
- if(text && *text)
- {
- char *x= strexpand(text, body_macros);
-
- if(x)
- {
- if(tabsize > 0)
- fexpand(fp,tabsize,x);
-
- else
- fputs(x,fp);
-
- free(x);
- }
- else err= __LINE__;
- }
-
- fputc('\n',fp);
- }
- }
- }
-
- return err;
- }
-
-
- /*
- ** TEXINFO
- */
-
-
- /* split `fun' into `chapter' and `section'.
- the string returned by this function has to be disposed via free() by the caller */
-
- static char *chapsec(char *fun, char **chapter, char **section)
- {
- char *c= strdup(fun);
- char *s= (char *)0;
-
- if(c)
- {
- if( (s= strchr(c,'/')) )
- *s++= '\0';
- }
-
- *chapter= c;
- *section= s;
-
- return c;
- }
-
- /*
- * The implementation of references in Texinfo perfectly silly :'(
- * Instead of offering one simple reference macro, Texinfo comes up
- * with context-sensitive @ref{}, @xref{}, @pref{}, ... and prints
- * a `See ...' and `See also ...' right in front of the it...
- */
-
- static int see_also(FILE *fp, char *refs, int flags)
- {
- int err= 0;
- char *buf= strdup(refs);
-
- #define isref(c) ( ('A'<=(c) && (c)<='Z') || \
- ('a'<=(c) && (c)<='z') || \
- ('0'<=(c) && (c)<='9') || ((c)=='_') || ((c)=='-') || ((c)=='/') || ((c)=='.') )
-
- if(buf)
- {
- /* make `s' the working pointer in `buf' */
- char *s= buf;
-
- /*
- * former revisions of ADOC used to indent the parsed references
- * by the same amount of white space as the first. Actually we
- * do not indent them amymore, so out it goes....
- */
-
- /* indentation string of the first reference */
- #if 0
- char *indent= (char *)0;
- #endif
-
- int num_refs= 0;
-
- while( *s && (err==0) )
- {
- char *l, *r;
-
- /* move `l' and `r' to the left and right end of a reference in `s' */
-
- for(l=s; *l && !isref(*l); l++) ;
- for(r=l; *r && isref(*r); r++) ;
-
- /* terminate the reference string with a '\0' */
- if(*r) *r++= '\0';
-
- /* save the indentation of the first reference */
- #if 0
- if(num_refs == 0)
- {
- if( (indent= strdup(s)) )
- {
- char *t= indent;
-
- while(*t==' ' || *t=='\t')
- ++t;
-
- *t= '\0';
- }
- else err= __LINE__;
- }
- #endif
-
- /* move `s' behind the reference */
- s= r;
-
- if( *l && (err==0) )
- {
- /* look for a function `l' and initialize `fun' to it's name */
- char *fun= (char *)0;
-
- /*fprintf(stderr,"--> @ref{%s} ?\n",l);*/
-
- if( getfun(l) )
- fun= strdup(l);
-
- else if( !strchr(l,'/') )
- {
- /*
- * Okay, we tried it the easy way but perhaps this is a reference
- * into the library without the library name in front of it.
- * Let's try appending `l' to the the current library name...
- */
-
- char *f= getfun( (char *)0 );
-
- if(f)
- {
- char *x, *xl, *xr;
-
- if( (x= chapsec(f, &xl, &xr)) )
- {
- size_t len= strlen(xl) + 1 + strlen(l) + 1;
- char *y= (char *)malloc( len * sizeof(char) );
-
- if(y)
- {
- sprintf(y,"%s/%s",xl,l);
-
- /*fprintf(stderr,"--> @ref{%s} ?\n",y);*/
-
- if( getfun(y) )
- fun= strdup(y);
-
- free(y);
- }
- else err= __LINE__;
-
- free(x);
- }
- else err= __LINE__;
- }
- else /* no current function? */
- err= __LINE__;
- }
-
- if(err == 0)
- {
- /* print the reference */
-
- if( fun )
- {
- char *cs, *chapter, *section;
-
- if( (cs= chapsec(fun, &chapter, §ion)) )
- {
- if(flags & TEXI_ITEMIZE_REFERENCES)
- {
- if(num_refs==0)
- fprintf(fp,"@itemize\n");
-
- fprintf(fp,"@item\n@xref{%s %s}.\n",chapter,section);
- }
- else /* not itemized */
- {
- if( (num_refs==0) && (flags & TEXI_GROUP_SECTIONS) )
- fprintf(fp,"@group\n");
-
- fprintf(fp,"%s{%s %s},\n", (num_refs==0) ? "@*@xref"
- : "@ref"
- , chapter
- , section
- );
- }
-
- free(cs);
- }
- else err= __LINE__;
-
- free(fun);
- }
- else /* !fun */
- {
- if(flags & TEXI_ITEMIZE_REFERENCES)
- {
- if(num_refs==0)
- fprintf(fp,"@itemize\n");
-
- fprintf(fp,"@item\nSee @file{%s}\n",l);
- }
- else /* not itemized */
- {
- if( (num_refs==0) && (flags & TEXI_GROUP_SECTIONS) )
- fprintf(fp,"@group\n");
-
- fprintf(fp,"%s{%s},\n",((num_refs==0) ? "@*See @file":"@file"),l);
- }
- }
-
- /* now at least one reference is printed */
- ++num_refs;
- }
- }
- }
-
- if(num_refs > 0)
- {
- if(flags & TEXI_ITEMIZE_REFERENCES)
- fprintf(fp,"@end itemize\n");
-
- else /* not itemized */
- {
- if(flags & TEXI_GROUP_SECTIONS)
- fprintf(fp,"@end group\n");
-
- fprintf(fp,"for more information.\n");
- }
- }
-
- #if 0
- if(indent)
- free(indent);
- #endif
-
- free(buf);
- }
- else err= __LINE__;
-
- #undef isref
-
- return err;
- }
-
-
- int gen_texinfo_header(FILE *fp, char *fname, char **header_macros)
- {
- int err= 0;
-
- char *default_header=
- "\\input texinfo @c -*-texinfo-*-\n"
- "@comment %%**start of header\n"
- "@setfilename PROJECT.guide\n"
- "@settitle Autodocs for @code{PROJECT}\n"
- "@paragraphindent 0\n"
- "@iftex\n"
- "@afourpaper\n"
- "@headings double\n"
- "@finalout\n"
- "@setchapternewpage on\n" /* odd */
- "@end iftex\n"
- "@comment %%**end of header\n\n"
- "@ifinfo\n"
- "@node Top\n"
- "@top\n"
- "This document describes @code{PROJECT} version EDITION.\n\n" /* was @value{EDITION} */
- "@noindent Copyright @copyright{} COPYRIGHT\n"
- "@end ifinfo\n\n"
- "@titlepage\n"
- "@title PROJECT\n"
- "@subtitle Documentation taken from source code\n"
- "@subtitle Edition for Version EDITION\n"
- "@subtitle @today\n"
- "@author AUTHOR\n\n"
- "@page\n"
- "@vskip 0pt plus 1filll\n"
- "Copyright @copyright{} COPYRIGHT\n"
- "@end titlepage\n\n";
-
- if(fname && *fname)
- {
- FILE *fh= fopen(fname,"r");
-
- if(fh)
- {
- char *header= (char *)0;
- size_t header_size= 0;
-
- /* compute the size of the header file */
-
- #ifdef BUGGY_FTELL
-
- do {
-
- (void)fgetc(fh);
-
- if(!feof(fh))
- ++header_size;
-
- } while(!feof(fh) || ferror(fh))
-
- #else /* ftell() works fine */
-
- if( fseek(fh,0L,2L) >= 0) /* 2 == OFFSET_END */
- header_size= ftell(fh);
-
- else
- err= __LINE__;
-
- #endif /* BUGGY_FTELL */
-
- if(!ferror(fh) && header_size > 0)
- {
- if(fseek(fh,-header_size,1L) < 0) /* 1 == OFFSET_CURRENT */
- err= __LINE__;
- }
- else err= __LINE__;
-
-
- /* load the header */
-
- if(err == 0)
- {
- if( (header= (char *)malloc( (header_size + 1) * sizeof(char) )) )
- {
- fread(header, sizeof(char), header_size, fh);
- header[header_size]= '\0';
-
- if( ferror(fh) )
- {
- free(header);
- header= (char *)0;
- err= __LINE__;
- }
- }
- else err= __LINE__;
- }
-
- if(err == 0)
- {
- char *x= strexpand(header, header_macros);
-
- if(x)
- {
- fputs(x,fp);
- free(x);
- }
- else /* out of memory */
- err= __LINE__;
- }
-
- fclose(fh);
- }
- }
-
- else /* !fname */
- {
- char *x= strexpand(default_header, header_macros);
-
- if(x)
- {
- fputs(x,fp);
- free(x);
- }
- else /* out of memory */
- err= __LINE__;
- }
-
- return err;
- }
-
-
-
- int gen_texinfo(FILE *fp, int tabsize, int flags, char *body_environment, char **body_macros)
- {
- int err= 0;
- char *fun, *sec;
-
- /* main menu:
- create a @menu with an entry for each library.
- an additional entry will be created for the function index */
-
- if(err == 0)
- {
- char *last_chapter = (char *)0; /* last printed chapter */
- char *last_cs = (char *)0; /* string allocated for `last_chapter' */
-
- fprintf(fp,"@menu\n");
-
- for(fun= stepfun(0); fun && (err==0); fun= stepfun(1))
- {
- char *cs, *chapter, *section;
-
- if( (cs= chapsec(fun, &chapter, §ion)) )
- {
- if( !last_chapter || strcmp(last_chapter, chapter) )
- {
- fprintf(fp,"* %s::\n", chapter);
-
- if(last_cs)
- free(last_cs);
-
- last_cs = cs;
- last_chapter = chapter;
- }
- else
- free(cs);
- }
- else /* out of memory */
- err= __LINE__;
- }
-
- if(last_cs)
- free(last_cs);
-
- fprintf(fp, "\n"
- "* Function Index::\n"
- "@end menu\n\n");
- }
-
- #if 0
-
- /* create one single (flat) menu for functions mapped to
- @chapters. This code is obsolete since we introduced
- the hierarchical layout with libraries mapped to
- @chapters and functions mapped to @sections. */
-
- if(err == 0)
- {
- fprintf(fp,"@menu\n");
-
- for(fun= stepfun(0); fun && (err==0); fun= stepfun(1))
- {
- char *cs, *chapter, *section;
-
- if( (cs= chapsec(fun, &chapter, §ion)) )
- {
- fprintf(fp,"* %s %s::\n", chapter, section);
- free(cs);
- }
- else /* out of memory */
- err= __LINE__;
- }
-
- fprintf(fp, "\n"
- "* Function Index::\n"
- "@end menu\n\n");
- }
-
- #endif
-
- /* chapters & sections */
-
- if(err == 0)
- {
- char *last_chapter = (char *)0;
- char *last_cs = (char *)0;
-
- for(fun= stepfun(0); fun && (err==0); fun= stepfun(1))
- {
- char *cs, *chapter, *section;
-
- if( (cs= chapsec(fun, &chapter, §ion)) )
- {
- if( !last_chapter || strcmp(last_chapter, chapter) )
- {
- /*
- * Start a new library
- */
-
- fprintf(fp, "\n"
- "@node %s\n"
- "@chapter %s\n\n"
- ,chapter
- ,chapter
- );
-
- /* print a sub menu for the current chapter */
-
- pushfun();
- {
- int done;
- char *sub_fun;
-
- fprintf(fp,"@menu\n");
- for(sub_fun= fun, done= 0; sub_fun && (err==0) && !done; sub_fun= stepfun(1))
- {
- char *sub_cs, *sub_chapter, *sub_section;
-
- if( (sub_cs= chapsec(sub_fun, &sub_chapter, &sub_section)) )
- {
- if( (done= strcmp(sub_chapter, chapter)) == 0 )
- fprintf(fp,"* %s %s::\n", sub_chapter, sub_section);
-
- free(sub_cs);
- }
- else err= __LINE__;
- }
- fprintf(fp,"@end menu\n\n");
- }
- popfun();
-
- if(last_cs)
- free(last_cs);
-
- last_cs = cs;
- last_chapter = chapter;
- }
-
- else /* we didn't start a new page for the chapter */
- {
- if(flags & TEXI_FUNCTION_NEWPAGE)
- fprintf(fp,"@page\n");
- }
-
- /*
- * Begin a new function
- */
-
- fprintf(fp, "\n"
- "@node %s %s\n"
- "@section %s\n"
- "@findex %s\n"
- "\n"
- ,chapter, section
- ,section
- ,section
- );
-
- if(flags & TEXI_TABLE_FUNCTIONS)
- fprintf(fp,"@table @b\n");
-
- for(sec= stepsec(0); sec && (err == 0); sec= stepsec(1))
- {
- char *text= getsec(sec);
-
- if(text && *text)
- {
-
- if(flags & TEXI_TABLE_FUNCTIONS)
- fprintf(fp,"@item %s\n",sec);
- else
- fprintf(fp,"@b{%s}\n",sec); /* was @strong{} or @code{} */
- /*fprintf(fp,"@noindent\n@b{%s}\n",sec);*/
-
-
- if( (flags & TEXI_PARSE_REFERENCES) && strcmp(sec,"SEE ALSO") == 0 )
- err= see_also(fp, text, flags);
-
- else /* ! "SEE ALSO" */
- {
- char *x= strexpand(text,body_macros);
-
- if(x)
- {
- fprintf(fp,"@noindent\n"
- "@%s\n",body_environment);
-
- if(flags & TEXI_GROUP_SECTIONS)
- fprintf(fp,"@group\n");
-
- if(tabsize > 0)
- fexpand(fp,tabsize,x);
- else
- fputs(x,fp);
-
- if(flags & TEXI_GROUP_SECTIONS)
- fprintf(fp,"@end group\n");
-
- fprintf(fp,"@end %s\n"
- "@refill\n",body_environment);
-
- free(x);
- }
- else /* out of memory */
- err= __LINE__;
- }
- }
- /* else (!text) -> no error */
-
- fprintf(fp,"\n");
- }
-
- if(flags & TEXI_TABLE_FUNCTIONS)
- fprintf(fp,"@end table\n");
- }
- else /* out of memory */
- err= __LINE__;
- }
-
- if(last_cs)
- free(last_cs);
- }
-
- /* index */
-
- if(err == 0)
- {
- fprintf(fp, "@node Function Index\n"
- "@unnumbered Function Index\n"
- "@printindex fn\n"
- "\n"
- "@page\n"
- "@contents\n"
- "@bye\n");
- }
-
- return err;
- }
-